package fileno

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"strings"
	"sync"
	"time"

	"github.com/ledongthuc/pdf"
	"github.com/xuri/excelize/v2"
)

const (
	LLM_HOST               = "http://10.100.8.72:18888/v1/chat/completions"
	HOST                   = "https://syapi.sytechnology.com"
	TOKEN                  = "205fbc07-9b2c-48a3-bad3-bb19b510b0f3"
	SheetName              = "Sheet1"
	FileName               = "file4.xlsx"
	HeaderRowIndex         = 2
	MaxConcurrentDownloads = 100 // 设置最大并发下载数
	// 38969 条数据
)

type ChatRequest struct {
	Model    string    `json:"model"`
	Messages []Message `json:"messages"`
}

type Message struct {
	Role    string `json:"role"`
	Content string `json:"content"`
}

type ExcelInfo struct {
	FileId string // 文件物理ID
	FileNo string // 文件编号
	Text   string // 提取的文本
}

type Choice struct {
	Message Message `json:"message"`
}

type ChoicesWrapper struct {
	Choices []Choice `json:"choices"`
}

type FileDetails struct {
	FileNo string `json:"fileNo"`
}

func SendChatRequest(content string) (*FileDetails, error) {
	chatReq := ChatRequest{
		Model: "openchat_3.5",
		Messages: []Message{
			{
				Role:    "user",
				Content: fmt.Sprintf("请将以下文本提取编号(fileNo)，并以json格式返回，只输出json，例子(编号: xxxxxx，中文解释编号后面接一个冒号再接文件编号)\r\n\r\n。%s", content),
			},
		},
	}
	// 将请求数据编码为JSON
	reqBody, err := json.Marshal(chatReq)
	if err != nil {
		return nil, err
	}

	// 创建HTTP请求
	req, err := http.NewRequest("POST", LLM_HOST, bytes.NewBuffer(reqBody))
	if err != nil {
		return nil, err
	}
	req.Header.Set("Content-Type", "application/json")

	// 发送请求
	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	// 读取响应
	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var wrapper ChoicesWrapper
	err = json.Unmarshal(respBody, &wrapper)
	if err != nil {
		return nil, err
	}

	if len(wrapper.Choices) > 0 {
		var fileDetails FileDetails
		err := json.Unmarshal([]byte(wrapper.Choices[0].Message.Content), &fileDetails)
		if err != nil {
			return nil, err
		}
		return &fileDetails, nil
	} else {
		return nil, fmt.Errorf("wrapper.Choices is empty")
	}
}

// 封装重试逻辑的函数
func RetrySendChatRequest(content string, maxAttempts int, delay time.Duration) (*FileDetails, error) {
	var fileDetails *FileDetails
	var err error

	for attempt := 1; attempt <= maxAttempts; attempt++ {
		fileDetails, err = SendChatRequest(content)
		if err == nil && fileDetails.FileNo != "" {
			return fileDetails, nil // 成功获取数据，返回结果
		}
		if attempt < maxAttempts {
			time.Sleep(delay) // 等待指定的延迟时间后再次尝试
		}
	}

	// 返回最后一次尝试的错误
	if err != nil {
		return nil, err
	}
	return fileDetails, nil
}

func readFile() []string {
	var list []string
	// 读取file.xlsx
	f, err := excelize.OpenFile("../" + FileName)
	if err != nil {
		log.Fatalf("无法打开文件: %v", err)
	}
	defer f.Close() // 确保在函数结束时关闭文件

	// 获取工作表 Sheet1 上的所有单元格
	rows, err := f.GetRows(SheetName)
	if err != nil {
		log.Fatalf("无法获取行: %v", err)
	}

	// 确定“文件物理ID”所在的列索引
	var filePhysicalIDColIndex int = -1
	for colIndex, colCell := range rows[HeaderRowIndex-1] { // 假设第二行是表头
		if colCell == "文件物理ID" {
			filePhysicalIDColIndex = colIndex
			break
		}
	}

	// 如果找到了“文件物理ID”列
	if filePhysicalIDColIndex != -1 {
		// 遍历除表头外的所有行
		for _, row := range rows[HeaderRowIndex:] {
			// 检查“文件物理ID”列是否有值
			if filePhysicalIDColIndex < len(row) && row[filePhysicalIDColIndex] != "" {
				// 输出或处理整行数据
				// for _, cell := range row {
				// 	fmt.Printf("%s\t", cell)
				// }
				// fmt.Printf("%s \n", row[filePhysicalIDColIndex])
				list = append(list, row[filePhysicalIDColIndex])
			}
		}
	} else {
		log.Println("未找到包含 '文件物理ID' 的列")
	}

	return list
}

func writeFile(list []string, wg *sync.WaitGroup) {
	outputDir := "../pdf"
	semaphore := make(chan struct{}, MaxConcurrentDownloads)

	// 确保输出目录存在
	if err := os.MkdirAll(outputDir, os.ModePerm); err != nil {
		fmt.Println("Error creating directories:", err)
		return
	}

	for _, fileId := range list {
		wg.Add(1)
		go func(fileId string) {
			defer wg.Done()
			semaphore <- struct{}{}        // 获取信号量的令牌
			defer func() { <-semaphore }() // 释放信号量的令牌

			outputFilename := fmt.Sprintf("%s.pdf", fileId)
			outputPath := filepath.Join(outputDir, outputFilename)

			// 检查文件是否已经存在且大小大于0
			if fileInfo, err := os.Stat(outputPath); err == nil && fileInfo.Size() > 0 {
				fmt.Printf("File %s already exists and is not empty, skipping download.\n", outputPath)
				return // 文件存在且非空，跳过当前循环，不再下载
			}

			// 下载文件的逻辑
			downloadFile := func(url, outputPath string) error {
				// 发送GET请求
				resp, err := http.Get(url)
				if err != nil {
					return fmt.Errorf("error while downloading file: %v", err)
				}
				defer resp.Body.Close()

				// 检查HTTP响应状态
				if resp.StatusCode != http.StatusOK {
					return fmt.Errorf("server returned non-200 status: %d %s", resp.StatusCode, resp.Status)
				}

				// 创建文件
				outFile, err := os.Create(outputPath)
				if err != nil {
					return fmt.Errorf("error while creating file: %v", err)
				}
				defer outFile.Close()

				// 将响应流复制到文件
				_, err = io.Copy(outFile, resp.Body)
				if err != nil {
					return fmt.Errorf("error while copying file: %v", err)
				}
				return nil
			}

			url := fmt.Sprintf("%s/file/getFile/%s?access_token=%s", HOST, fileId, TOKEN)

			// 尝试下载文件
			if err := downloadFile(url, outputPath); err != nil {
				fmt.Println(err)
				// 如果下载失败或文件大小为0，则尝试重新下载
				if fileInfo, err := os.Stat(outputPath); os.IsNotExist(err) || fileInfo.Size() == 0 {
					fmt.Printf("Attempting to re-download file %s\n", outputPath)
					if err := downloadFile(url, outputPath); err != nil {
						fmt.Println("Failed to download file on retry:", err)
						return
					}
				}
			}

			fmt.Printf("File %s downloaded successfully to %s\n", fileId, outputPath)
		}(fileId)
	}
	wg.Wait()
}

func parsePDF(list []string, wg *sync.WaitGroup) []ExcelInfo {
	var excelList []ExcelInfo
	var mutex sync.Mutex // 创建一个互斥锁
	semaphore := make(chan struct{}, MaxConcurrentDownloads)

	for _, fileId := range list {
		wg.Add(1)
		go func(fileId string) {
			defer wg.Done()
			defer func() {
				if r := recover(); r != nil {
					fmt.Println("Recovered from panic:", r, "FileID:", fileId)
				}
				<-semaphore // 无论如何都释放信号量的令牌
			}()
			semaphore <- struct{}{} // 获取信号量的令牌

			filePath := fmt.Sprintf("../pdf/%s.pdf", fileId)
			f, r, err := pdf.Open(filePath)
			if err != nil {
				fmt.Println("Error opening PDF file:", err, fileId)
				return
			}
			defer f.Close()

			var textBuilder strings.Builder
			b, err := r.GetPlainText()
			if err != nil {
				fmt.Println("Error getting plain text from PDF:", err)
				return
			}

			if _, err := io.Copy(&textBuilder, b); err != nil {
				fmt.Println("Error reading text from PDF:", err)
				return
			}
			text := textBuilder.String()

			re := regexp.MustCompile(`编号：[A-Z0-9]+`)
			match := re.FindString(text)

			// resp, err := RetrySendChatRequest(text, 3, 0)
			// if err != nil {
			// 	fmt.Println("未能成功获取文件编号:", err, fileId)
			// 	return
			// } else if resp.FileNo == "" {
			// 	fmt.Println("获取到的文件编号不完整:", resp, fileId)
			// 	return
			// }

			mutex.Lock() // 在修改excelList之前加锁
			excelList = append(excelList, ExcelInfo{
				FileId: fileId,
				FileNo: match,
				Text:   text,
			})
			mutex.Unlock() // 修改完成后解锁
		}(fileId)
	}
	wg.Wait()
	return excelList
}

func writeExcel(list []ExcelInfo) {
	f, err := excelize.OpenFile("../" + FileName)
	if err != nil {
		fmt.Println("Error opening Excel file:", err)
		return
	}
	defer func() {
		if err := f.Close(); err != nil {
			fmt.Println("Error closing Excel file:", err)
		}
	}()

	// 获取工作表中所有的行
	rows, err := f.GetRows(SheetName)
	if err != nil {
		fmt.Println("Error reading rows:", err)
		return
	}

	// 假设第二行是标题行，找出各个关键列的索引
	titleRow := rows[HeaderRowIndex-1]
	idColIndex, fileNoColIndex := -1, -1
	for col, cell := range titleRow {
		switch cell {
		case "文件物理ID":
			idColIndex = col
		case "文件中的编号":
			fileNoColIndex = col
		}
	}

	// 检查是否所有需要的列都找到了
	if idColIndex == -1 || fileNoColIndex == -1 {
		fmt.Println("Error: One or more required columns not found")
		return
	}

	// 遍历list并更新数据
	for _, info := range list {
		for rowIndex, row := range rows {
			if rowIndex < HeaderRowIndex { // 跳过前两行（第一行和标题行）
				continue
			}
			if len(row) > idColIndex && row[idColIndex] == info.FileId {
				// 计算单元格地址并更新值
				fileNoCell, _ := excelize.CoordinatesToCellName(fileNoColIndex+1, rowIndex+1)

				f.SetCellValue(SheetName, fileNoCell, info.FileNo)
				break
			}
		}
	}

	// 保存文件
	if err := f.SaveAs("../" + FileName); err != nil {
		fmt.Println("Error saving Excel file:", err)
	}
}

func WriteFileNo() {
	// 读取excel
	list := readFile()

	// WaitGroup等待所有goroutine完成
	var wg sync.WaitGroup
	// list := []string{"1388176068194172929"}
	// 下载文件
	writeFile(list, &wg)

	// list := []string{"3675379810785837056"}
	// WaitGroup等待所有解析goroutine完成
	var parseWg sync.WaitGroup
	// 解析文件
	parseList := parsePDF(list, &parseWg)
	// 写入excel
	writeExcel(parseList)
}
